/*
 * Copyright (C) 2010-2011 Enrique Lara (enrique.posix2.lara@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package app.timetogo.provider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;

import android.database.Cursor;
import android.database.SQLException;

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;

import android.net.Uri;

import android.provider.BaseColumns;
import android.provider.LiveFolders;

import android.text.TextUtils;

import app.timetogo.R;

import app.timetogo.provider.Tables.Alarms;

import app.timetogo.util.Log;

import java.util.Calendar;
import java.util.HashMap;

public final class TimeToGoProvider extends ContentProvider {
    private static final String TAG = "TimeToGo";
    private static final String DATABASE_NAME = "time_to_go.db";
    private static final int DATABASE_VERSION = 4;
    private static HashMap<String, String> sAlarmsProjectionMap;
    private static HashMap<String, String> sLiveFolderProjectionMap;
    private static final int ALARMS = 1;
    private static final int ALARM_ID = 2;
    private static final int LIVE_FOLDER_ALARMS = 3;
    private static final UriMatcher sUriMatcher;

    private static class DatabaseHelper extends SQLiteOpenHelper {
        DatabaseHelper(final Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(final SQLiteDatabase db) {
            StringBuilder ddl = new StringBuilder();
            ddl.append("CREATE TABLE ").append(Alarms.TABLE_NAME);
            ddl.append(" (");
            ddl.append(BaseColumns._ID).append(" INTEGER PRIMARY KEY,");
            ddl.append(Alarms.ENABLED).append(" INTEGER,");
            ddl.append(Alarms.HOUR).append(" INTEGER,");
            ddl.append(Alarms.MINUTE).append(" INTEGER,");
            ddl.append(Alarms.DAYS_IN_WEEK).append(" INTEGER,");
            ddl.append(Alarms.AGENCY_ID).append(" INTEGER,");
            ddl.append(Alarms.STOP).append(" TEXT,");
            ddl.append(Alarms.ROUTE).append(" TEXT,");
            ddl.append(Alarms.DIRECTION).append(" TEXT,");
            ddl.append(Alarms.TIME_MAX).append(" INTEGER,");
            ddl.append(Alarms.TIME_MIN).append(" INTEGER,");
            ddl.append(Alarms.LABEL).append(" TEXT,");
            ddl.append(Alarms.RINGTONE).append(" TEXT,");
            ddl.append(Alarms.VIBRATE).append(" INTEGER,");
            ddl.append(Alarms.IMAGE).append(" INTEGER");
            ddl.append(");");
            db.execSQL(ddl.toString());
        }

        @Override
        public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");

            if (oldVersion <= DATABASE_VERSION) {
                db.execSQL("DROP TABLE IF EXISTS " + Alarms.TABLE_NAME);
                onCreate(db);
            }
        }
    }

    private DatabaseHelper mOpenHelper;

    @Override
    public boolean onCreate() {
        mOpenHelper = new DatabaseHelper(getContext());

        return true;
    }

    @Override
    public String getType(final Uri uri) {
        switch (sUriMatcher.match(uri)) {
            case ALARMS:
            case LIVE_FOLDER_ALARMS:
                return Alarms.CONTENT_TYPE;

            case ALARM_ID:
                return Alarms.CONTENT_ITEM_TYPE;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    @Override
    public Uri insert(final Uri uri, final ContentValues initialValues) {
        // Validate the requested uri
        if (sUriMatcher.match(uri) != ALARMS) {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        ContentValues values;

        if (initialValues != null) {
            values = new ContentValues(initialValues);
        } else {
            values = new ContentValues();
        }

        final Calendar c = Calendar.getInstance();

        // Make sure that the required fields are set
        if (values.containsKey(Alarms.ENABLED) == false) {
            values.put(Alarms.ENABLED, 0);
        }

        if (values.containsKey(Alarms.HOUR) == false) {
            values.put(Alarms.HOUR, c.get(Calendar.HOUR_OF_DAY));
        }

        if (values.containsKey(Alarms.MINUTE) == false) {
            values.put(Alarms.MINUTE, c.get(Calendar.MINUTE));
        }

        if (values.containsKey(Alarms.DAYS_IN_WEEK) == false) {
            values.put(Alarms.DAYS_IN_WEEK, 0);
        }

        if (values.containsKey(Alarms.STOP) == false) {
            values.put(Alarms.STOP, "D03"); //Station.L_ENFANT_PLAZA.getCode());
        }

        if (values.containsKey(Alarms.ROUTE) == false) {
            values.put(Alarms.ROUTE, "BL"); //Constants.BLUE);
        }

        if (values.containsKey(Alarms.DIRECTION) == false) {
            values.put(Alarms.DIRECTION, "J03"); //Station.FRANCONIA_SPRINGFIELD.getCode());
        }

        if (values.containsKey(Alarms.TIME_MAX) == false) {
            values.put(Alarms.TIME_MAX, 17);
        }

        if (values.containsKey(Alarms.TIME_MIN) == false) {
            values.put(Alarms.TIME_MIN, 7);
        }

        if (values.containsKey(Alarms.VIBRATE) == false) {
            values.put(Alarms.VIBRATE, 1);
        }

        if (values.containsKey(Alarms.IMAGE) == false) {
            values.put(Alarms.IMAGE, R.drawable.time_to_transit);
        }

        //        if (values.containsKey(Alarms.RINGTONE) == false) {
        //            values.put(Alarms.RINGTONE, android.provider.Settings.System.DEFAULT_RINGTONE_URI.toString());
        //        }
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final long rowId = db.insert(Alarms.TABLE_NAME, Alarms.STOP, values);

        if (rowId > 0) {
            final Uri itemUri = ContentUris.withAppendedId(Alarms.CONTENT_URI, rowId);
            getContext().getContentResolver().notifyChange(itemUri, null);

            return itemUri;
        }

        throw new SQLException("Failed to insert row into " + uri);
    }

    @Override
    public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) {
        final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables(Alarms.TABLE_NAME);

        switch (sUriMatcher.match(uri)) {
            case ALARMS:
                qb.setProjectionMap(sAlarmsProjectionMap);

                break;

            case ALARM_ID:
                qb.setProjectionMap(sAlarmsProjectionMap);
                qb.appendWhere(BaseColumns._ID + "=" + uri.getPathSegments().get(1));

                break;

            case LIVE_FOLDER_ALARMS:
                qb.setProjectionMap(sLiveFolderProjectionMap);

                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        // If no sort order is specified use the default
        String orderBy;

        if (TextUtils.isEmpty(sortOrder)) {
            orderBy = Alarms.DEFAULT_SORT_ORDER;
        } else {
            orderBy = sortOrder;
        }

        // Get the database and run the query
        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        final Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);

        // Tell the cursor what uri to watch, so it knows when its source data changes
        c.setNotificationUri(getContext().getContentResolver(), uri);

        return c;
    }

    @Override
    public int update(final Uri uri, final ContentValues values, final String where, final String[] whereArgs) {
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;

        switch (sUriMatcher.match(uri)) {
            case ALARMS:
                count = db.update(Alarms.TABLE_NAME, values, where, whereArgs);

                break;

            case ALARM_ID:

                final String alarmId = uri.getPathSegments().get(1);
                count = db.update(Alarms.TABLE_NAME, values, BaseColumns._ID + "=" + alarmId + ((!TextUtils.isEmpty(where)) ? (" AND (" + where + ')') : ""), whereArgs);

                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);

        return count;
    }

    @Override
    public int delete(final Uri uri, final String where, final String[] whereArgs) {
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;

        switch (sUriMatcher.match(uri)) {
            case ALARMS:
                count = db.delete(Alarms.TABLE_NAME, where, whereArgs);

                break;

            case ALARM_ID:

                final String alarmId = uri.getPathSegments().get(1);
                count = db.delete(Alarms.TABLE_NAME, BaseColumns._ID + "=" + alarmId + ((!TextUtils.isEmpty(where)) ? (" AND (" + where + ')') : ""), whereArgs);

                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        getContext().getContentResolver().notifyChange(uri, null);

        return count;
    }

    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(Tables.AUTHORITY, Alarms.TABLE_NAME, ALARMS);
        sUriMatcher.addURI(Tables.AUTHORITY, Alarms.TABLE_NAME + "/#", ALARM_ID);
        sUriMatcher.addURI(Tables.AUTHORITY, "live_folders/" + Alarms.TABLE_NAME, LIVE_FOLDER_ALARMS);

        sAlarmsProjectionMap = new HashMap<String, String>();
        sAlarmsProjectionMap.put(BaseColumns._ID, BaseColumns._ID);

        /* Timing */
        sAlarmsProjectionMap.put(Alarms.ENABLED, Alarms.ENABLED);
        sAlarmsProjectionMap.put(Alarms.HOUR, Alarms.HOUR);
        sAlarmsProjectionMap.put(Alarms.MINUTE, Alarms.MINUTE);
        sAlarmsProjectionMap.put(Alarms.DAYS_IN_WEEK, Alarms.DAYS_IN_WEEK);
        /* Criteria */
        sAlarmsProjectionMap.put(Alarms.AGENCY_ID, Alarms.AGENCY_ID);
        sAlarmsProjectionMap.put(Alarms.STOP, Alarms.STOP);
        sAlarmsProjectionMap.put(Alarms.ROUTE, Alarms.ROUTE);
        sAlarmsProjectionMap.put(Alarms.DIRECTION, Alarms.DIRECTION);
        sAlarmsProjectionMap.put(Alarms.TIME_MAX, Alarms.TIME_MAX);
        sAlarmsProjectionMap.put(Alarms.TIME_MIN, Alarms.TIME_MIN);
        /* Representation */
        sAlarmsProjectionMap.put(Alarms.LABEL, Alarms.LABEL);
        sAlarmsProjectionMap.put(Alarms.RINGTONE, Alarms.RINGTONE);
        sAlarmsProjectionMap.put(Alarms.VIBRATE, Alarms.VIBRATE);
        sAlarmsProjectionMap.put(Alarms.IMAGE, Alarms.IMAGE);

        // Support for Live Folders.
        sLiveFolderProjectionMap = new HashMap<String, String>();
        sLiveFolderProjectionMap.put(BaseColumns._ID, BaseColumns._ID + " AS " + BaseColumns._ID);
        sLiveFolderProjectionMap.put(LiveFolders.NAME, Alarms.LABEL + " AS " + LiveFolders.NAME);

        // Add more columns here for more robust Live Folders.
    }
}
